<template>
  <div>
    <div class="container">
      <div class="w-upload">
        <div class="upload-select">
          <i class="el-icon-upload"></i>
          <div class="desc">将文件拖到此处，或点击上传图片</div>
        </div>
        <input type="file"
               class="upload-input"
               multiple
               ref="uploadInput"
               accept="image/*"
               @change="handleFileChange" />
      </div>
      <div class="mt20"
           v-loading.lock="loading">
        <div class="mb20">
          <el-radio-group v-model="quality"
                          size="small">
            <el-radio-button :label="0.8">清晰优先</el-radio-button>
            <el-radio-button :label="0.7">普通压缩</el-radio-button>
            <el-radio-button :label="0.5">缩小优先</el-radio-button>
          </el-radio-group>
          <el-input-number v-model="quality"
                           :precision="2"
                           :step="0.1"
                           :min="0.1"
                           :max="1"
                           class="ml10"></el-input-number>
          <el-tooltip placement="top"
                      class="ml10">
            <div slot="content">
              数值越小压缩图片越小，但会导致图片质量降低。范围在 0.1 ~ 1 之间。

              如果您已经调整该值到最大或最小都发现没有增加(或减少)压缩效果,说明已经压缩到极限了, 实际压缩效果通常和图片格式有关
            </div>
            <i class="el-icon-info"></i>
          </el-tooltip>
        </div>
        <div class="w-btn">
          <el-button type="primary"
                     :disabled="compressDis"
                     :loading="loading"
                     @click="handleCompress">开始压缩</el-button>
          <el-button type="danger"
                     plain
                     :disabled="!imgList.length"
                     @click="handleDeleteAll">一键清空</el-button>
          <el-button type="primary"
                     plain
                     :disabled="downloadAllDis"
                     @click="handleDownloadAll">打包下载</el-button>
        </div>
        <!-- 选择图片列表 -->

        <div v-for="item in imgList"
             :key="item.id"
             class="img-item">
          <img :src="item.img"
               alt=""
               class="img" />
          <div class="name-size-info">
            <span class="name">{{item.name}}</span>
            <div class="size"
                 v-if="!item.compressedGraphSize">未压缩（{{item.originalSize}}）</div>
            <div class="size success"
                 v-else>已压缩（{{item.originalSize}} <i class="el-icon-right"></i> {{item.compressedGraphSize}}）</div>
          </div>
          <i class="download el-icon-download"
             v-show="item.compressedGraphSize"
             @click="handleDownload(item.name,item.compressedGraphFile)"></i>
          <!-- <el-progress :percentage="50"
                       class="progress"></el-progress> -->
        </div>

      </div>
    </div>
  </div>
</template>

<script>
import Compressor from 'compressorjs';
import JsZip from 'jszip';
import { validateImgOnlySuffix } from '@/utils/utils';

const UNCOMPRESSED = 'uncompression'; /* 未压缩 */
// const COMPRESSING = 'compressing'; /* 压缩中 */
const COMPRESSED = 'compressed'; /* 已压缩 */
export default {
  name: 'pictureCompression',
  data: function () {
    return {
      disabledbtn: false,
      loading: false,
      doms: {
        select: null,
        input: null
      },
      quality: 0.8,
      imgList: []
    };
  },
  created() {},
  mounted() {
    // this.doms.select = document.querySelector('.upload-select');
    this.doms.input = document.querySelector('.upload-input');
  },
  computed: {
    /* 压缩按钮是否禁用 */
    compressDis() {
      if (this.imgList.length == 0) return true;
      /* 对每一项函数都返回 true， 则这个方法返回 true */
      return this.imgList.every(
        (item) => item.compressedStatus != UNCOMPRESSED
      );
    },
    /* 下载按钮是否禁用 */
    downloadAllDis() {
      return !this.imgList.some(
        (item) => item.compressedStatus != UNCOMPRESSED
      );
    }
  },
  watch: {
    /* 改变压缩比例后，初始化压缩数据 */
    quality() {
      this.imgList.forEach((item) => {
        item.compressedGraphSize = '';
        item.compressedGraphFile = '';
        item.compressedStatus = UNCOMPRESSED;
      });
    }
  },
  methods: {
    /* 拖拽相关事件：给w-upload添加拖拽事件
    （需要input中设置隐藏，并且点击上传区域去手动触发input的点击事件）。
    目前是利用input默认的拖拽上传 */
    /* 拖拽的目标 */
    handleDrag() {},
    /* 放到何处 阻止默认行为 */
    handleAllowDrop(e) {
      e.preventDefault();
    },
    /* 拖拽的目的地 */
    handleDrop(e) {
      e.preventDefault();
      // console.log(e.dataTransfer.files);
      this.handleUploadFiles(e.dataTransfer.files);
    },

    /* 选择文件 */
    handleSelectFile() {
      // console.log(this.doms.input);
      // this.doms.input.click();
    },

    /* 选择文件的change事件 */
    handleFileChange(e) {
      this.handleUploadFiles(e.target.files);
    },

    /* 处理上传的图片 */
    handleUploadFiles(files) {
      for (const file of files) {
        /* 校验图片是否合法 */
        if (!validateImgOnlySuffix(file).boolean) {
          this.$message.error('请上传图片');
        } else {
          /* 显示预览图 */
          const reader = new FileReader();
          reader.onload = (e) => {
            this.imgList.unshift({
              id: Symbol('img'),
              img: e.target.result,
              name: file.name,
              /* 原图大小 */
              originalSize: this.handleFormattingImageSize(file.size),
              file,
              /* 压缩图大小 */
              compressedGraphSize: '',
              /* 压缩图文件 */
              compressedGraphFile: '',
              compressedStatus: UNCOMPRESSED,
              progress: 0
            });
          };
          reader.readAsDataURL(file);
        }
      }
      /* 清空input的值,防止相同文件上传时，不触发change事件 */
      this.doms.input.value = '';
    },

    /* 格式化显示大小 */
    handleFormattingImageSize(size) {
      if (size < 1024) return size + 'B';
      let data = size / 1024;
      if (data > 500) {
        return (data / 1024).toFixed(2) + 'MB';
      } else {
        return data.toFixed(2) + 'KB';
      }
    },

    /* 开始压缩 */
    handleCompress() {
      if (!this.imgList.length) return;
      this.$message.success('开始压缩');
      const list = this.imgList.filter(
        (item) => item.compressedStatus == UNCOMPRESSED
      );
      const p1 = Promise.all(
        list.map((item) => this.handleCompressorClass(item))
      );
      this.loading = true;
      p1.then((data) => {
        for (const { item, size, result } of data) {
          item.compressedGraphSize = size;
          item.compressedGraphFile = result;
          item.compressedStatus = COMPRESSED;
        }
        this.$message.success('压缩完成');
      })
        .catch(() => {
          this.$message.warning('压缩失败');
        })
        .finally(() => {
          this.loading = false;
        });
    },

    /* 处理Compressor类封装成一个Promise函数 */
    handleCompressorClass(item) {
      return new Promise((resolve, reject) => {
        new Compressor(item.file, {
          quality: this.quality,
          success: (result) => {
            const size = this.handleFormattingImageSize(result.size);
            resolve({ item, size, result });
          },
          error(err) {
            console.log(err.message);
            item.compressedStatus = UNCOMPRESSED;
            reject(err.message);
          }
        });
      });
    },
    /* 一键清空 */
    handleDeleteAll() {
      this.imgList = [];
    },
    /* 下载所有压缩过后的图片 */
    handleDownloadAll() {
      const list = this.imgList.filter(
        (item) => item.compressedGraphSize != ''
      );
      /* 这个是一张一张的下载 */
      // list.forEach((item) => {
      //   this.handleDownload(item);
      // });
      /* 下面是打包的压缩包下载 */
      const zip = new JsZip();
      list.forEach((item) => {
        // this.handleDownload(item);
        zip.file(item.name, item.compressedGraphFile);
      });
      zip
        .generateAsync({ type: 'blob' })
        .then((content) => {
          this.handleDownload('compressed-images.zip', content);
        })
        .catch((error) => {
          console.error('生成ZIP文件失败:', error);
        });
    },

    /* 下载图片/资源 */
    handleDownload(fileName, compressedGraphFile) {
      const url = window.URL.createObjectURL(compressedGraphFile);
      const a = document.createElement('a');
      a.style.display = 'none';
      a.href = url;
      a.download = fileName; // 设置下载的文件名
      document.body.appendChild(a);
      a.click();
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }
  }
};
</script>
<style>
@import './assets/css/reset.css';
@import './assets/css/main.css';

/* 解决表头不对齐问题，样式 */
body .el-table th.gutter {
  display: table-cell !important;
}

body .el-table colgroup.gutter {
  display: table-cell !important;
}
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background-color: #fff;
}
::-webkit-scrollbar-thumb {
  border-radius: 5px;
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  background-color: rgba(0, 0, 0, 0.1);
}

/* 修改时间选择器的宽度100% */
.el-date-editor--datetimerange.el-input,
.el-date-editor--datetimerange.el-input__inner {
  width: 100% !important;
}

/* 修改对话框头部样式 */
.el-dialog__header {
  background-color: #3d6cb0;
}
.el-dialog__header .el-dialog__title,
.el-dialog__header .el-dialog__headerbtn .el-dialog__close {
  color: #fff;
}

/* 删除样式 start */
.mlr10 {
  margin: 0 10px;
}
.display-inline-block {
  display: inline-block;
}
/* end */
</style>

<style lang="scss" scoped>
.container {
  width: 60%;
  margin: auto;
  padding: 30px;
  .w-upload {
    width: 100%;
    height: 100%;
    position: relative;
    // width: 300px;
    height: 300px;
    border: 1px dashed #666;
    .upload-select {
      position: absolute;
      z-index: 11;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      width: 100%;
      height: 100%;

      i {
        font-size: 70px;
        color: #666;
      }
      .desc {
        margin-top: 20px;
        font-size: 30px;
        color: #666;
      }
      &:hover {
        cursor: pointer;
      }
    }
    .upload-input {
      /* 这里设置相对定位重要，并且层级要比upload-select高 */
      position: relative;
      z-index: 12;
      width: 100%;
      height: 100%;
      opacity: 0;
      /* 如果设置为none，就需要去监听父级的点击事件并且手动触发input的点击事件，此时的话
      input可以定义在任何位置 */
      // display: none;
      &:hover {
        cursor: pointer;
      }
    }
    &:hover {
      border-color: #409eff;
    }
  }

  .img-item {
    position: relative;
    display: flex;
    align-items: center;
    margin: 10px 0;
    padding: 15px 40px 15px 15px;
    background-color: rgb(236, 245, 255);
    // border: 1px dashed #999;
    border-radius: 5px;
    .img {
      width: 140px;
      height: 140px;
      border-radius: 10px;
    }
    .name-size-info {
      flex: 1;
      margin-left: 20px;
      .name {
        font-size: 22px;
        color: #333;
      }
      .size {
        margin-top: 20px;
        font-size: 16px;
        color: #999;
      }
      .success {
        color: #409eff;
      }
    }
    .download {
      font-size: 30px;
      color: #409eff;
      &:hover {
        cursor: pointer;
      }
    }

    .progress {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
    }
  }
}
</style>